Conversation
BREAKING CHANGE: Mock server now uses generated OpenAPI types instead of simplified custom types
The mock server was using custom simplified types that didn't match the actual 3commas API structure. This caused consumers to receive different data structures than the real API provides.
## Critical Changes:
**bot_events structure:**
- Before: 11 fields (action, coin, type, status, price, size, order_type, order_size, order_position, is_market, created_at)
- After: 2 fields (message, created_at) - matching the real API
**Bot and Deal types:**
- Now use full tcmock.Bot and tcmock.Deal generated from OpenAPI spec
- Bot: ~50 fields matching real API instead of 4 custom fields
- Deal: ~100 fields matching real API instead of 8 custom fields
## Migration Guide:
### Before:
```go
mockServer.AddBot(server.Bot{
ID: 1, Name: "Test", Enabled: true, AccountID: 123,
})
mockServer.AddDeal(1, server.Deal{
ID: 101, BotID: 1, Status: "active",
Events: []server.BotEvent{
{Action: "place", Coin: "BTC", ...},
},
})
```
### After:
```go
mockServer.AddBot(server.NewBot(1, "Test", 123, true))
deal := server.NewDeal(101, 1, "USDT_BTC", "active")
server.AddBotEvent(&deal, "Placing base order. Price: 50000.0")
mockServer.AddDeal(deal)
```
## New Helper Functions:
- `server.NewBot()` - Create bot with sensible defaults
- `server.NewDeal()` - Create deal with required fields
- `server.AddBotEvent()` - Add event with message and timestamp
- `TestServer.AddBotEventToDeal()` - Add event to existing deal
Fixes the core issue where the mock didn't behave like the actual 3commas server.
Add ability to load go-vcr cassettes to populate mock server with real 3commas API responses. This enables testing against actual production data without manual mocking.
## Features
**Core API:**
- `LoadVCRCassette(path)` - Load single VCR cassette
- `LoadVCRCassettes(...paths)` - Load multiple cassettes
**What Gets Loaded:**
- ✅ Bots with ALL 50+ fields from real API
- ✅ Deals with ALL 100+ fields from real API
- ✅ **bot_events PRESERVED exactly as recorded** (critical for testing)
- ✅ Auto-creates minimal bots when deals reference non-existent bot IDs
**Behavior:**
- Only processes successful (2xx) responses
- Errors on duplicate IDs (ensures clean VCR preparation)
- Skips non-GET requests
- Pattern matches: /ver1/deals/{id}/show, /ver1/deals, /ver1/bots
## Usage Example
```go
func TestWithRealData(t *testing.T) {
mockServer := server.NewTestServer(t)
defer mockServer.Close()
// Load real API response from VCR cassette
mockServer.LoadVCRCassette("testdata/fixtures/my_deal")
// Deal now available with ALL real data including bot_events
resp, _ := http.Get(mockServer.URL() + "/ver1/deals/123/show")
var deal tcmock.Deal
json.NewDecoder(resp.Body).Decode(&deal)
// bot_events preserved from real 3commas API!
assert.Len(t, deal.BotEvents, 3)
}
```
## Why This Matters
VCR cassettes contain REAL complex data from 3commas that would be tedious to mock manually:
- Complex bot_events messages with actual trading activity
- All 100+ deal fields with real profit/loss calculations
- Actual account names, pairs, and trading strategies
This makes testing more realistic and maintainable.
## Dependencies
- Added gopkg.in/dnaeon/go-vcr.v3 for YAML parsing
## Tests
- TestLoadVCRCassette_SingleDeal - Basic loading and verification
- TestLoadVCRCassette_DuplicateError - Duplicate ID detection
- TestLoadVCRCassettes_Multiple - Loading multiple cassettes
- TestExampleVCRLoading - Example usage pattern
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| func (ts *TestServer) LoadVCRCassette(cassettePath string) error { | ||
| // Load cassette from file | ||
| c, err := cassette.Load(cassettePath) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to load VCR cassette %s: %w", cassettePath, err) |
There was a problem hiding this comment.
Ensure VCR cassette path includes .yaml extension
The new LoadVCRCassette forwards the caller’s path directly to cassette.Load, but the go‑vcr loader expects the actual filename including its .yaml suffix. Every new test and example invokes this helper with a basename (e.g. ../testdata/fixtures/deal_2376446537), assuming the library appends the extension, so cassette.Load will fail with “no such file or directory” and no data will be loaded. Either append .yaml in LoadVCRCassette before calling cassette.Load or update callers to pass the complete filename.
Useful? React with 👍 / 👎.
The mock server was using custom simplified types that didn't match the actual 3commas API structure. This caused consumers to receive different data structures than the real API provides.
Critical Changes:
bot_events structure:
Bot and Deal types: